package com.jtbd.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jtbd.dto.JwtPayloadEntity;
import com.jtbd.dto.JwtSimplePayloadEntity;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

@Configuration
public class JwtUtil {
    @Resource
    private ObjectMapper objectMapper;
    // jwt的密钥
    @Value("${jwt.secret}")
    private String secret;
    // jwt的过期时间
    @Value("${jwt.expire}")
    private long expire;
    // 用户转换 JWT令牌中的用户信息的map集合
    private final TypeReference<Map<String, Object>> typeReference = new TypeReference<>() {
    };
    // 生成JWT令牌 的key
    public static final String JWT_KEY = "token";
    // redis中的JWT令牌key
    public static final String JWT_REDIS_KEY = "token_";

    private SecretKey key;

    /**
     * 生成Redis键值
     *
     * @param uid 用户唯一标识符
     * @return 返回由JWT_REDIS_KEY前缀和用户ID组成的完整Redis键值
     */
    public static String redisTokenKey(String uid) {
        return JWT_REDIS_KEY + uid;
    }

    /**
     * 生成JWT令牌
     *
     * @param payloadEntity 令牌中的用户信息
     * @return 生成的JWT令牌字符串
     */
    public String generateToken(JwtSimplePayloadEntity payloadEntity) {
        if (key == null) {
            // 创建密钥
            key = Keys.hmacShaKeyFor(secret.getBytes());
        }
        // 构建JWT令牌
        return Jwts.builder()
                // 设置令牌类型为JWT
                .setHeaderParam("typ", "JWT")
                // 设置令牌主题为用户名
                .setSubject(payloadEntity.getUid().toString())
                // 添加用户信息到令牌中
                .addClaims(objectMapper.convertValue(payloadEntity, typeReference))
                // 设置令牌签发时间
                .setIssuedAt(new Date())
                // 设置令牌过期时间
                .setExpiration(new Date(System.currentTimeMillis() + expire * 1000))
                // 使用HS256算法和密钥签名
                .signWith(key, SignatureAlgorithm.HS256)
                // 生成紧凑格式的JWT字符串
                .compact();
    }

    /**
     * 生成JWT令牌
     *
     * @param claims 令牌中的用户信息
     * @return 生成的JWT令牌字符串
     */
    public String generateToken(JwtPayloadEntity claims) {
        if (key == null) {
            // 创建密钥
            key = Keys.hmacShaKeyFor(secret.getBytes());
        }
        // 构建JWT令牌
        return Jwts.builder()
                // 设置令牌类型为JWT
                .setHeaderParam("typ", "JWT")
                // 设置令牌主题为用户名
                .setSubject(claims.getUsername())
                // 添加用户信息到令牌中
                .addClaims(objectMapper.convertValue(claims, typeReference))
                // 设置令牌签发时间
                .setIssuedAt(new Date())
                // 设置令牌过期时间
                .setExpiration(new Date(System.currentTimeMillis() + expire * 1000))
                // 使用HS256算法和密钥签名
                .signWith(key, SignatureAlgorithm.HS256)
                // 生成紧凑格式的JWT字符串
                .compact();
    }

    /**
     * 验证JWT令牌
     *
     * @param token 待验证的JWT令牌字符串
     * @return 验证结果，true表示令牌有效，false表示令牌无效
     */
    public boolean validateToken(String token) {
        try {
            if (key == null) {
                // 创建密钥
                key = Keys.hmacShaKeyFor(secret.getBytes());
            }
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /**
     * 获取JWT令牌中的用户信息
     */
    public JwtPayloadEntity getRealInfoFromJwt(String token) {
        try {
            Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
            claims.getExpiration();
            JwtPayloadEntity jwtPayloadEntity = new JwtPayloadEntity();
            jwtPayloadEntity.setId(Long.parseLong(claims.getOrDefault("id", "0").toString()));
            jwtPayloadEntity.setUsername(claims.getOrDefault("username", "").toString());
            jwtPayloadEntity.setRole(claims.getOrDefault("role", "").toString());
            jwtPayloadEntity.setSignChar(claims.getOrDefault("signChar", "").toString());
            jwtPayloadEntity.setPassword(claims.getOrDefault("password", "").toString());
            return jwtPayloadEntity;
        } catch (Exception e) {
            return null;
        }
    }

}
